{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "nbsphinx": "hidden"
   },
   "outputs": [],
   "source": [
    "import open3d as o3d\n",
    "import numpy as np\n",
    "import os\n",
    "import sys\n",
    "\n",
    "# monkey patches visualization and provides helpers to load geometries\n",
    "sys.path.append('..')\n",
    "import open3d_tutorial as o3dtut\n",
    "# change to True if you want to interact with the visualization windows\n",
    "o3dtut.interactive = not \"CI\" in os.environ"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Visualization\n",
    "## Function draw_geometries\n",
    "Open3D provides a convenient visualization function `draw_geometries` which takes a list of geometry objects (`PointCloud`, `TriangleMesh`, or `Image`), and renders them together. We have implemented many functions in the visualizer, such as rotation, translation, and scaling via mouse operations, changing rendering style, and screen capture. Press `H` inside the window to print out a comprehensive list of functions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"Load a ply point cloud, print it, and render it\")\n",
    "sample_ply_data = o3d.data.PLYPointCloud()\n",
    "pcd = o3d.io.read_point_cloud(sample_ply_data.path)\n",
    "o3d.visualization.draw_geometries([pcd],\n",
    "                                  zoom=0.3412,\n",
    "                                  front=[0.4257, -0.2125, -0.8795],\n",
    "                                  lookat=[2.6172, 2.0475, 1.532],\n",
    "                                  up=[-0.0694, -0.9768, 0.2024])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "-- Mouse view control --\n",
    "  Left button + drag         : Rotate.\n",
    "  Ctrl + left button + drag  : Translate.\n",
    "  Wheel button + drag        : Translate.\n",
    "  Shift + left button + drag : Roll.\n",
    "  Wheel                      : Zoom in/out.\n",
    "\n",
    "-- Keyboard view control --\n",
    "  [/]          : Increase/decrease field of view.\n",
    "  R            : Reset view point.\n",
    "  Ctrl/Cmd + C : Copy current view status into the clipboard.\n",
    "  Ctrl/Cmd + V : Paste view status from clipboard.\n",
    "\n",
    "-- General control --\n",
    "  Q, Esc       : Exit window.\n",
    "  H            : Print help message.\n",
    "  P, PrtScn    : Take a screen capture.\n",
    "  D            : Take a depth capture.\n",
    "  O            : Take a capture of current rendering settings.\n",
    "```\n",
    "\n",
    "<div class=\"alert alert-info\">\n",
    "    \n",
    "**Note:** \n",
    "\n",
    "In some operating systems (e.g., macOS), the visualization window may not respond to keyboard input. This is usually because the console retains the input focus instead of passing it to the visualization window. Running with `pythonw` instead of `python` will resolve this issue.\n",
    "\n",
    "</div>\n",
    "\n",
    "<div class=\"alert alert-info\">\n",
    "    \n",
    "**Note:** \n",
    "\n",
    "In addition to `draw_geometries`, Open3D has a set of sibling functions with more advanced functionality. `draw_geometries_with_custom_animation` allows the programmer to define a custom view trajectory and play an animation in the GUI. `draw_geometries_with_animation_callback` and `draw_geometries_with_key_callback` accept Python callback functions as input. The callback function is called in an automatic animation loop, or upon a key press event. See [Customized visualization](../visualization/customized_visualization.rst) for details.\n",
    "\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Store view point\n",
    "In the beginning, the point cloud is rendered upside down.\n",
    "\n",
    "![bad view](../../_static/visualization/visualization/badview.png)\n",
    "\n",
    "After adjusting view points using `left-click + drag`, we can reach a better view point.\n",
    "\n",
    "![color view](../../_static/visualization/visualization/color.png)\n",
    "\n",
    "To retain this view point, press `Ctrl + C`. The view point will be translated into a json string stored in clipboard. When you move the camera to a different view, such as:\n",
    "\n",
    "![new view](../../_static/visualization/visualization/newview.png)\n",
    "\n",
    "You can get back to the original view by pressing `Ctrl + V`.\n",
    "\n",
    "![color view](../../_static/visualization/visualization/color.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Rendering styles\n",
    "Open3D `Visualizer` supports several rendering styles. For example, pressing `L` will switch between a Phong lighting and a simple color rendering. Pressing `2` shows points colored based on their x-coordinate.\n",
    "\n",
    "![colormap jet](../../_static/visualization/visualization/colormap_jet.png)\n",
    "\n",
    "The color map can also be adjusted by, for example, pressing `Shift + 4`. This changes jet color map to hot color map.\n",
    "\n",
    "![colormap hot](../../_static/visualization/visualization/colormap_hot.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Geometry primitives\n",
    "The code below generates a box, a sphere, and a cylinder using `create_box`, `create_sphere`, and `create_cylinder`. The box is painted in red, the sphere is painted in blue, and the cylinder is painted in green. Normals are computed for all meshes to support Phong shading (see [Visualize 3D mesh](../geometry/mesh.ipynb#visualize-a-3d-mesh) and [Surface normal estimation](../geometry/mesh.ipynb#surface-normal-estimation)). We can even create a coordinate axis using `create_coordinate_frame`, with its origin point set at (-2, -2, -2)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"Let's define some primitives\")\n",
    "mesh_box = o3d.geometry.TriangleMesh.create_box(width=1.0,\n",
    "                                                height=1.0,\n",
    "                                                depth=1.0)\n",
    "mesh_box.compute_vertex_normals()\n",
    "mesh_box.paint_uniform_color([0.9, 0.1, 0.1])\n",
    "mesh_sphere = o3d.geometry.TriangleMesh.create_sphere(radius=1.0)\n",
    "mesh_sphere.compute_vertex_normals()\n",
    "mesh_sphere.paint_uniform_color([0.1, 0.1, 0.7])\n",
    "mesh_cylinder = o3d.geometry.TriangleMesh.create_cylinder(radius=0.3,\n",
    "                                                          height=4.0)\n",
    "mesh_cylinder.compute_vertex_normals()\n",
    "mesh_cylinder.paint_uniform_color([0.1, 0.9, 0.1])\n",
    "mesh_frame = o3d.geometry.TriangleMesh.create_coordinate_frame(\n",
    "    size=0.6, origin=[-2, -2, -2])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`draw_geometries` takes a list of geometries and renders them all together. Alternatively, `TriangleMesh` supports a + operator to combine multiple meshes into one. We recommend the first approach since it supports a combination of different geometries (e.g., a mesh can be rendered in tandem with a point cloud)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"We draw a few primitives using collection.\")\n",
    "o3d.visualization.draw_geometries(\n",
    "    [mesh_box, mesh_sphere, mesh_cylinder, mesh_frame])\n",
    "\n",
    "print(\"We draw a few primitives using + operator of mesh.\")\n",
    "o3d.visualization.draw_geometries(\n",
    "    [mesh_box + mesh_sphere + mesh_cylinder + mesh_frame])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Draw line set\n",
    "To draw lines, it is necessary to define a `LineSet` with a set of points and a set of edges (pairs of point indices). The example below creates custom points and edges (denoted as `lines`) to make a box. Color is optional - red color `[1,0,0]` is assigned to each edge in this example."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"Let's draw a box using o3d.geometry.LineSet.\")\n",
    "points = [\n",
    "    [0, 0, 0],\n",
    "    [1, 0, 0],\n",
    "    [0, 1, 0],\n",
    "    [1, 1, 0],\n",
    "    [0, 0, 1],\n",
    "    [1, 0, 1],\n",
    "    [0, 1, 1],\n",
    "    [1, 1, 1],\n",
    "]\n",
    "lines = [\n",
    "    [0, 1],\n",
    "    [0, 2],\n",
    "    [1, 3],\n",
    "    [2, 3],\n",
    "    [4, 5],\n",
    "    [4, 6],\n",
    "    [5, 7],\n",
    "    [6, 7],\n",
    "    [0, 4],\n",
    "    [1, 5],\n",
    "    [2, 6],\n",
    "    [3, 7],\n",
    "]\n",
    "colors = [[1, 0, 0] for i in range(len(lines))]\n",
    "line_set = o3d.geometry.LineSet(\n",
    "    points=o3d.utility.Vector3dVector(points),\n",
    "    lines=o3d.utility.Vector2iVector(lines),\n",
    ")\n",
    "line_set.colors = o3d.utility.Vector3dVector(colors)\n",
    "o3d.visualization.draw_geometries([line_set])"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Edit Metadata",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
